package ldh.im.fxbase.dao;

import ldh.im.fxbase.data.pojo.ImDepartment;
import ldh.im.fxbase.data.pojo.ext.ImDepartmentExt;
import ldh.im.fxbase.data.pojo.status.ImDepartmentStatus;
import ldh.im.fxbase.util.DbUtil;
import org.apache.commons.dbutils.ResultSetHandler;
import org.apache.commons.dbutils.handlers.ArrayListHandler;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.apache.commons.dbutils.handlers.ScalarHandler;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

public class ImDepartmentDao extends BaseDao {

    private static final String TABLE_NAME = "im_department";
    private static final String DEPARTMENT_COLUMN  = "d.id, d.currentUserId, d.name, d.code, d.parentCode, d.description, d.status statusValue, " +
            "d.managerUserId, d.otherManagerUserIds, d.ext1, d.ext2, d.createTime, d.updateTime";

    public List<ImDepartment> getDepartments() throws SQLException {
        return DbUtil.transaction((queryRunner, connection) -> {
            String sql = String.format("select %s from im_department d where d.status = ? ", DEPARTMENT_COLUMN);
            List<ImDepartmentExt> imDepartmentExts = queryRunner.query(connection, sql, new BeanListHandler<>(ImDepartmentExt.class), ImDepartmentStatus.enable.getValue());
            return imDepartmentExts.stream().map(m->m).collect(Collectors.toList());
        });
    }

    public ImDepartment getDepartmentByCode(String code) throws SQLException {
        return DbUtil.transaction((queryRunner, connection) -> {
            String sql = String.format("select %s from im_department d where d.code = ?", DEPARTMENT_COLUMN);
            ImDepartment imDepartment = queryRunner.query(connection, sql, new BeanHandler<ImDepartment>(ImDepartment.class), code);
            return imDepartment;
        });
    }

    public List<ImDepartment> getDepartmentByCodes(List<String> codeList) throws SQLException {
        if (codeList.size() < 1) return new ArrayList<>();
        return DbUtil.transaction((queryRunner, connection) -> {
            String idParams = codeList.stream().map(c-> "?").collect(Collectors.joining(","));
            String sql = String.format("select %s from im_department d where d.code in (%s)", DEPARTMENT_COLUMN, idParams);
            List<ImDepartmentExt> imDepartments = queryRunner.query(connection, sql, new BeanListHandler<ImDepartmentExt>(ImDepartmentExt.class), codeList.stream().toArray());
            return imDepartments.stream().map(m->m).collect(Collectors.toList());
        });
    }

    public List<ImDepartmentExt> getDepartmentsTopLevel() throws SQLException {
        return DbUtil.transaction((queryRunner, connection) -> {
            String sql = String.format("select %s from im_department d where d.parentCode is null", DEPARTMENT_COLUMN);
            List<ImDepartmentExt> imDepartmentExts = queryRunner.query(connection, sql, new BeanListHandler<ImDepartmentExt>(ImDepartmentExt.class));
            return imDepartmentExts.stream().map(m->m).collect(Collectors.toList());
        });
    }

    public List<ImDepartmentExt> getDepartmentsByParentCode(String parentCode) throws SQLException {
        return DbUtil.transaction((queryRunner, connection) -> {
            String sql = String.format("select %s from im_department d where d.parentCode = ?", DEPARTMENT_COLUMN);
            List<ImDepartmentExt> imDepartmentExts = queryRunner.query(connection, sql, new BeanListHandler<ImDepartmentExt>(ImDepartmentExt.class), parentCode);
            return imDepartmentExts.stream().map(m->m).collect(Collectors.toList());
        });
    }

    public void insertDepartment(ImDepartment imDepartment) throws SQLException {
        DbUtil.transaction((queryRunner, connection) -> {
            ResultSetHandler<Long> resultSetHandler = new ScalarHandler();
            String sql = String.format("insert into im_department(code, name, managerUserId, description, parentCode," +
                    " ext1, ext2, status, otherManagerUserIds, createTime, updateTime) values(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
            Long id = queryRunner.insert(connection, sql, resultSetHandler, departmentToInsertArray(imDepartment));
            imDepartment.setId(id);
            return imDepartment;
        });
    }

    public void batchInserts(List<ImDepartment> imDepartmentList) throws SQLException {
        if (imDepartmentList.size() < 1) return;
        DbUtil.transaction((queryRunner, connection) -> {
            String sql = String.format("insert into im_department(code, currentUserId, name, managerUserId, description, parentCode," +
                    " ext1, ext2, status, otherManagerUserIds, createTime, updateTime) values(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
            Object[][] paras = imDepartmentList.stream().map(d-> departmentToInsertArray(d)).toArray(Object[][]::new);
            List<Object[]> results = queryRunner.insertBatch(connection, sql, new ArrayListHandler(), paras);

            for(int i=0; i<results.size(); i++) {
                Long bigInteger = (Long) results.get(i)[0];
                imDepartmentList.get(i).setId(bigInteger.longValue());
            }
            return imDepartmentList;
        });
    }

    public void updateDepartment(ImDepartment imDepartment) throws SQLException {
        DbUtil.transaction((queryRunner, connection) -> {
            String sql = String.format("update im_department set name = ?, managerUserId = ?, description = ?, parentCode = ?," +
                    ", ext1 = ?, ext2 = ?, status = ?, otherManagerUserIds = ?, createTime = ?, updateTime = ? where code = ?");
                    Object[] paras = departmentToInsertArray(imDepartment);
            queryRunner.update(connection, sql, paras);
            return imDepartment;
        });
    }

    public void batchUpdates(List<ImDepartment> imDepartmentList) throws SQLException {
        DbUtil.transaction((queryRunner, connection) -> {
            String sql = String.format("update im_department set name = ?, managerUserId = ?, description = ?, parentCode = ?," +
                    "ext1 = ?, ext2 = ?, status = ?, otherManagerUserIds = ?, createTime = ?, updateTime = ? where code = ?");
            Object[][] paras = imDepartmentList.stream().map(d-> departmentToUpdateArray(d)).toArray(Object[][]::new);
            queryRunner.batch(connection, sql, paras);
            return imDepartmentList;
        });
    }

    private Object[] departmentToInsertArray(ImDepartment imDepartment) {
        return new Object[] {
                imDepartment.getCode(), imDepartment.getCurrentUserId(), imDepartment.getName(), imDepartment.getManagerUserId(), imDepartment.getDescription(), imDepartment.getParentCode(),
                imDepartment.getExt1(), imDepartment.getExt2(), valueEnum(imDepartment.getStatus()),
                Optional.ofNullable(imDepartment.getOtherManagerUserIdSet()).stream().map(e->e.toString()).collect(Collectors.joining(",")),
                imDepartment.getCreateDateTime(), imDepartment.getUpdateDateTime()
        };
    }

    private Object[] departmentToUpdateArray(ImDepartment imDepartment) {
        return new Object[] {
                imDepartment.getName(), imDepartment.getManagerUserId(), imDepartment.getDescription(), imDepartment.getParentCode(),
                imDepartment.getExt1(), imDepartment.getExt2(), valueEnum(imDepartment.getStatus()),
                Optional.ofNullable(imDepartment.getOtherManagerUserIdSet()).stream().map(e->e.toString()).collect(Collectors.joining(",")),
                imDepartment.getCreateDateTime(), imDepartment.getUpdateDateTime(), imDepartment.getCode()
        };
    }
}
